// ExtractingFilePath.cpp

#include "StdAfx.h"

#include "Common/FileSystem/Wildcard.h"

#include "ExtractingFilePath.h"

#include <string.h>

namespace Common
{
namespace FileSystem
{

static CString ReplaceIncorrectChars(const CString &s)
{
  #ifdef _WIN32
  CString res;
  for (int i = 0; i < s.GetLength(); i++)
  {
    wchar_t c = s[i];
    if (c < 0x20 || c == '*' || c == '?' || c == '<' || c == '>'  || c == '|' || c == ':' || c == '"')
      c = '_';
    res += c;
  }
  res.TrimRight();
  while (!res.IsEmpty() && res[res.GetLength() - 1] == '.')
    res.Delete(res.GetLength() - 1);
  return res;
  #else
  return s;
  #endif
}

#ifdef _WIN32
static LPCTSTR g_ReservedNames[] =
{
  _T("CON"), _T("PRN"), _T("AUX"), _T("NUL")
};

static bool CheckTail(const CString &name, int len)
{
  int dotPos = name.Find(_T('.'));
  if (dotPos < 0)
    dotPos = name.GetLength();
  CString s = name.Left(dotPos);
  s.TrimRight();
  return (s.GetLength() != len);
}

static bool CheckNameNum(const CString &name, const wchar_t *reservedName)
{
	int len = wcslen(reservedName);
  if (name.GetLength() <= len)
    return true;
  if (name.Left(len).CompareNoCase(reservedName) != 0)
    return true;
  wchar_t c = name[len];
  if (c < L'0' || c > L'9')
    return true;
  return CheckTail(name, len + 1);
}

static bool IsSupportedName(const CString &name)
{
  for (int i = 0; i < sizeof(g_ReservedNames) / sizeof(g_ReservedNames[0]); i++)
  {
    const wchar_t *reservedName = g_ReservedNames[i];
	int len =  wcslen(reservedName); 
    if (name.GetLength() < len)
      continue;
    if (name.Left(len).CompareNoCase(reservedName) != 0)
      continue;
    if (!CheckTail(name, len))
      return false;
  }
  if (!CheckNameNum(name, _T("COM")))
    return false;
  return CheckNameNum(name, _T("LPT"));
}
#endif

static CString GetCorrectFileName(const CString &path)
{
  if (path == _T("..") || path == _T("."))
    return CString();
  return ReplaceIncorrectChars(path);
}

void MakeCorrectPath(CStringVector &pathParts)
{
  for (size_t i = 0; i < pathParts.size();)
  {
    CString &s = pathParts[i];
    s = GetCorrectFileName(s);
    if (s.IsEmpty())
		pathParts.erase(pathParts.begin() +  i);
    else
    {
      #ifdef _WIN32
      if (!IsSupportedName(s))
        s = (CString)_T("_") + s;
      #endif
      i++;
    }
  }
}

CString MakePathNameFromParts(const CStringVector &parts)
{
  CString result;
  for (size_t i = 0; i < parts.size(); i++)
  {
    if (i != 0)
      result += CHAR_PATH_SEPARATOR;
    result += parts[i];
  }
  return result;
}

CString GetCorrectFsPath(const CString &path)
{
  CString res = GetCorrectFileName(path);
  #ifdef _WIN32
  if (!IsSupportedName(res))
    res = (CString)_T("_") + res;
  #endif
  return res;
}
  
CString GetCorrectFullFsPath(const CString &path)
{
  CStringVector parts;
  Common::FileSystem::SplitPathToParts(path, parts);
  for (size_t i = 0; i < parts.size(); i++)
  {
    CString &s = parts[i];
    #ifdef _WIN32
    while (!s.IsEmpty() && s[s.GetLength() - 1] == '.')
      s.Delete(s.GetLength() - 1);
    if (!IsSupportedName(s))
      s = (CString)_T("_") + s;
    #endif
  }
  return MakePathNameFromParts(parts);
}

}
}